package com.ideaaedi.springcloud.jd.commonspring.refresher;

import com.ideaaedi.commonds.clazz.ClazzUtil;
import com.ideaaedi.commonds.io.IOUtil;
import com.ideaaedi.commonds.path.PathUtil;
import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
import com.ideaaedi.springcloud.jd.commonds.constant.JdSymbolConstant;
import com.ideaaedi.springcloud.jd.commonds.entity.CodeMsgProvider;
import com.ideaaedi.springcloud.jd.commonds.support.EnumDescriptor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 刷新基础code-msg说明文档<br/>
 * 注：在本地环境调试时会进行刷新. 且当次刷新的文档，要下次启动时才能看到.（因为此文档即时性要求不高，先这样简单处理.）
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.A
 */
@Slf4j
@Component
@Profile(BaseConstant.ENV_DEV)
public class CodeMsgMarkdownRefresher implements ApplicationRunner {
    
    /** 通用响应编码 的文档标题 */
    @Value("${api-doc.code-msg.common-markdown.title:通用响应编码}")
    private String commonCodeMsgMdTitle;
    
    
    /** 通用响应编码 的表格头内容(使用英文逗号分割) */
    @Value("${api-doc.code-msg.common-markdown.table-headers:序号,code,name,描述}")
    private String commonCodeMsgMdTableHeaders;
    
    @Override
    public void run(ApplicationArguments args) throws ClassNotFoundException {
        String projectRootDir = PathUtil.getProjectRootDir(CodeMsgMarkdownRefresher.class);
        boolean isJar = projectRootDir.endsWith(".jar");
        if (isJar) {
            log.info("curr run env is jar. skip refresh code msg markdown.");
            return;
        }
        String targetMdFilepath = projectRootDir.replace("/target/classes/",
                "/src/main/resources/api-doc-common/code-msg.md");
        boolean filepathIsCorrect = new File(targetMdFilepath).exists();
        if (!filepathIsCorrect) {
            log.info("filepath is not correct. skip refresh code msg markdown. determine filepath -> {}", filepathIsCorrect);
            return;
        }
    
        // 准备数据
        List<List<String>> rowList = prepareData();
    
        // 刷新markdown文件
        generateMdTable(targetMdFilepath, commonCodeMsgMdTitle, rowList);
        log.info("refresh code msg markdown. see {}", targetMdFilepath);
    }
    
    /**
     * 准备数据
     */
    @NotNull
    private List<List<String>> prepareData() throws ClassNotFoundException {
        List<List<String>> rowList = new ArrayList<>(128);
        rowList.add(Arrays.asList(commonCodeMsgMdTableHeaders.split(JdSymbolConstant.COMMA)));
        List<String> clazzNameList = ClazzUtil.getClazzName(CodeMsgProvider.class.getPackage().getName(), true);
        for (String clazzName : clazzNameList) {
            Class<?> clazz = Class.forName(clazzName);
            if (CodeMsgProvider.class.isAssignableFrom(clazz) && clazz.isEnum()) {
                //noinspection unchecked
                for (Enum<?> enumConstant : ((Class<Enum<?>>) clazz).getEnumConstants()) {
                    List<String> rowItemslist = new ArrayList<>(4);
                    rowItemslist.add(String.valueOf(rowList.size()));
                    String code = ((CodeMsgProvider) enumConstant).code();
                    String name = enumConstant.name();
                    String description;
                    if (enumConstant instanceof EnumDescriptor) {
                        description = ((EnumDescriptor) enumConstant).obtainDescription();
                    } else {
                        description = ((CodeMsgProvider) enumConstant).message();
                    }
                    rowItemslist.add(code);
                    rowItemslist.add(name);
                    rowItemslist.add(description);
                    rowList.add(rowItemslist);
                }
            }
        }
        return rowList;
    }
    
    /**
     * 生成md表格文件
     * <p>
     * <p>
     * 使用示例
     * <pre>
     *    public static void main(String[] args) {
     *         List<List<String>> dataList = new ArrayList<>();
     *         dataList.add(Lists.newArrayList("序号","code","msg","说明"));
     *         dataList.add(Lists.newArrayList("1","000000","success","成功"));
     *         dataList.add(Lists.newArrayList("2","100000","fail","失败"));
     *         generateMdTable("/tmp/code-msg-desc.md", "响应编码字典", dataList);
     *     }
     * </pre>
     *
     * @param filepath md文件路径。形如：/tmp/code-msg-desc.md
     * @param title 文件内容的标题（一级标题）
     * @param dataList 文件内容（第一个list为标题, dataList中的每个list的size可以不一样， 以标题list的size为准）
     */
    private static void generateMdTable(String filepath, String title, List<List<String>> dataList) {
        final String colSeparator = "|";
        final String headerSeparator = "---";
        final String blank = " ";
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
        StringBuilder mdBuilder = new StringBuilder(512);
        
        /// step1. 构建md标题
        mdBuilder.append("# ").append(title);
        mdBuilder.append(System.lineSeparator());
        
        /// step2. 构建md表格
        List<String> headerItemList = dataList.get(0);
        int headerItemSize = headerItemList.size();
        // 组装头，如： |  姓名  | 年龄 |
        for (String headerItem : headerItemList) {
            mdBuilder.append(colSeparator).append(blank).append(headerItem).append(blank);
        }
        mdBuilder.append(colSeparator).append(System.lineSeparator());
        
        // 组装分割线，如：| ---- | ---- |
        for (int i = 0; i < headerItemSize; i++) {
            mdBuilder.append(colSeparator).append(blank).append(headerSeparator).append(blank);
        }
        mdBuilder.append(colSeparator).append(System.lineSeparator());
        
        // 组装内容，如：| 张三 | 30 |
        for (int i = 1; i < dataList.size(); i++) {
            List<String> colItemList = dataList.get(i);
            Objects.requireNonNull(colItemList, "colItemList should not be null.");
            int colItemSize = colItemList.size();
            for (int j = 1; j <= headerItemSize; j++) {
                mdBuilder.append(colSeparator).append(blank).append(j <= colItemSize ? colItemList.get(j-1) : blank).append(blank);
            }
            mdBuilder.append(colSeparator).append(System.lineSeparator());
        }
        
        IOUtil.writeContentToFile(mdBuilder.toString(), new File(filepath));
    }
}
